package com.jg.xmlSchema2JsonSchema.xsd;

import com.jg.xmlSchema2JsonSchema.XmlUtil;
import com.jg.xmlSchema2JsonSchema.xsd.util.XsdReader;
import com.jg.xmlSchema2JsonSchema.xsd.util.XsdUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class BaseXsdReader {
    protected Map<String, XsComplexType> complexTypeMap = new HashMap<String, XsComplexType>();
    protected Map<String, XsSimpleType> simpleTypeMap = new HashMap<String, XsSimpleType>();
    protected XsdReader xsdReader = new XsdReader();
    protected Element rootElement;
    protected XsElement[] rootXsElements;
    protected XsElement rootXsElement;

    public BaseXsdReader(InputStream inputStream) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.parse(inputStream);
        init(document);
    }

    public XsdReader getXsdReaderUtil() {
        return xsdReader;
    }

    public BaseXsdReader(String filename) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document document = db.parse(new File(filename));
        init(document);
    }

    private void init(Document document) throws Exception {
        rootElement = (Element) document.getDocumentElement();
        rootXsElements = XsdUtil.getElements(rootElement).toArray(new XsElement[0]);
        rootXsElement = XsdUtil.getElements(rootElement).toArray(new XsElement[0])[0];
        parseComplexTypes(rootElement, complexTypeMap);
        parseSimpleTypes(rootElement, simpleTypeMap);
        xsdReader.setComplexTypeMap(complexTypeMap);
        xsdReader.setSimpleTypeMap(simpleTypeMap);
        parseXSD(document);
    }

    public static void parseComplexTypes(Element rootElement, Map<String, XsComplexType> complexTypeMap) {
        List<Element> complexTypeList = XmlUtil.getChildElements(rootElement,
                XMLConstants.XSD_DEFAULT_NAMESPACE + ":" + XMLConstants.XSD_COMPLEX_TYPE);
        for (Element element : complexTypeList) {
            XsComplexType xsComplexType = new XsComplexType(element);
            complexTypeMap.put(xsComplexType.getName(), xsComplexType);
            System.out.println("XsComplexType:" + xsComplexType.getName());
        }
    }

    public static void parseSimpleTypes(Element rootElement, Map<String, XsSimpleType> simpleTypeMap) {
        List<Element> simpleTypeList = XmlUtil.getChildElements(rootElement,
                XMLConstants.XSD_DEFAULT_NAMESPACE + ":" + XMLConstants.XSD_SIMPLETYPE);
        for (Element element : simpleTypeList) {
            XsSimpleType xsSimpleType = new XsSimpleType(element);
            simpleTypeMap.put(xsSimpleType.getName(), xsSimpleType);
            System.out.println("XsSimpleType:" + xsSimpleType.getName());
        }
    }

    protected abstract void parseXSD(Document document) throws Exception;

    public XsElement[] getRootXsElements() {
        return rootXsElements;
    }

    public XsElement getRootXsElement() {
        return rootXsElements[0];
    }

    public XsComplexType getComplexType(String name) {
        return complexTypeMap.get(name);
    }

    public Map<String, XsComplexType> getComplexTypeMap() {
        return complexTypeMap;
    }

    public XsSimpleType getSimpleType(String name) {
        return simpleTypeMap.get(name);
    }

    public Map<String, XsSimpleType> getSimpleTypeMap() {
        return simpleTypeMap;
    }

    protected List<XsEnumeration> getEnumeration(XsComplexType complexType, String attributeName) {
        XsAttribute attribute = complexType.getAttribute(attributeName);
        return getEnumeration(attribute);
    }

    protected List<XsEnumeration> getEnumeration(XsAttribute attribute) {
        XsSimpleType simpleType = attribute.getSimpleType();
        return simpleType.getRestriction().getEnumerations();
    }

    public List<XsAttribute> getAttributes(XsElement element) throws Exception {
        return xsdReader.getAttributes(element);
    }

    public XsAttribute getAttribute(XsElement element, String name) throws Exception {
        return xsdReader.getAttribute(element, name, true);
    }

    public List<XsAttribute> getAttributes(XsComplexType complexType) throws Exception {
        return xsdReader.getAttributes(complexType);
    }

    public XsAttribute getAttribute(XsComplexType complexType, String name) throws Exception {
        return xsdReader.getAttributes(complexType, name);
    }

    public List<XsElement> getElements(XsComplexType complexType) throws Exception {
        return xsdReader.getElements(complexType);
    }

    public List<XsEnumeration> getEnumerations(XsAttribute attribute) {
        XsSimpleType simpleType = attribute.getSimpleType();
        return simpleType.getRestriction().getEnumerations();
    }
}
